import logging
import traceback

from django.db import transaction
from django.db.models import Q
from apps.goods.models import Goods
from rest_framework.response import Response
from rest_framework import status
from apps.goods.serializers import GoodsSerializer
from django.core.paginator import Paginator, EmptyPage
from utils.cache_server import GoodsCache
from demo import settings
from utils.process_response import ProcessResponse
from .tasks import update_goods_stock

logger = logging.getLogger("django")
# 初始化商品缓存的redis客户端
redis_client = GoodsCache(host=settings.redis_host, port=settings.redis_port, db=settings.redis_db_for_goods)

class GoodsMain:
    @staticmethod
    def search_goods(request):
        """  获取商品信息  """
        try:
            name = request.GET.get("name")
            page = request.GET.get("page")
            page_size = request.GET.get("pageSize")
            id = request.GET.get("id")
            if not page:
                page = 1
            if not page_size:
                page_size = 10

            # 构建查询条件
            query = Q()
            if name:
                query &= Q(name__icontains=name)
            if id:
                query &= Q(id=id)

            # 分页处理
            goods_list = Goods.objects.filter(query).order_by("id")
            paginator = Paginator(goods_list, page_size)
            count = paginator.count

            try:
                page_obj = paginator.page(page)
            except EmptyPage:
                return ProcessResponse.fail(msg="页码超出范围")

            # 获取当前页ID列表
            ids = [i.id for i in page_obj.object_list]
            cached_data = redis_client.get_many(ids)

            # 找出缺失的缓存项, val为{}
            missing_ids = [id_ for id_, val in zip(ids, cached_data) if not val]
            missing_goods = goods_list.filter(id__in=missing_ids)
            missing_data = GoodsSerializer(missing_goods, many=True).data
            # 批量创建缓存
            redis_client.set_many(missing_data)
            not_cache_dict = {i["id"]: i for i in missing_data}

            # 构建最终结果
            final_result = []

            for idx, id_ in enumerate(ids):
                if cached_data[idx]:
                    final_result.append(cached_data[idx])
                else:
                    final_result.append(not_cache_dict[id_])
            res = {
                "count": count,
                "results": final_result
            }
            return ProcessResponse.success(data=res)

        except Exception as e:
            print(traceback.format_exc())
            logger.error(f"查询失败: {str(e)}")
            return Response({"error": "Internal Server Error"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    @staticmethod
    def add_goods(request):
        """ 添加商品信息  """
        serializer = GoodsSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            # 添加缓存信息
            redis_client.set_one(serializer.data)
            return ProcessResponse.success(data=serializer.data)
        else:
            return ProcessResponse.params_error()

    @staticmethod
    def alter_goods(request, id):
        """ 修改商品信息,全量修改  """
        try:
            instance = Goods.objects.get(id=id)
            serializer = GoodsSerializer(instance, data=request.data)
            if serializer.is_valid():
                # 高并发采用延迟双删的策略
                redis_client.double_delay_delete(id=id, instance=instance, data=serializer.data)
                return ProcessResponse.success()
            else:
                return ProcessResponse.params_error()
        except Goods.DoesNotExist:
            return ProcessResponse.fail(msg='商品不存在')

    @staticmethod
    def delete_goods(id):
        """ 删除商品信息  """
        try:
            instance = Goods.objects.get(id=id)
            with transaction.atomic():
                instance.delete()
            # redis 删除缓存
            redis_client.delete_cache(id)
            return ProcessResponse.success()
        except Goods.DoesNotExist:
            return ProcessResponse.fail(msg='商品不存在')

    @staticmethod
    def pre_reduce_stock(request, id):
        """
            1. 先从redis中获取库存
            2. 如果redis中没有库存, 则从数据库中获取库存
        """
        # 校验参数
        quantity = request.data.get('quantity')
        if not (quantity or isinstance(quantity, int)):
            return ProcessResponse.params_error()

        # 1. 从缓存中获取数据
        data = redis_client.get_one(id)
        # 2. 如果缓存中没有数据, 则从数据库中获取数据
        if not data:
            try:
                with transaction.atomic():
                    # 获取商品并加行级锁
                    instance = Goods.objects.select_for_update().get(id=id)
                    if instance.stock >= quantity:
                        # 缓存数据
                        redis_client.set_one({
                            "id": instance.id,
                            "name": instance.name,
                            "category": instance.category,
                            "price": float(instance.price),
                            "stock": instance.stock - quantity,
                            "avatar": instance.avatar
                        })
                        instance.stock -= quantity
                        instance.save()
                    else:
                        return ProcessResponse.fail(msg="库存不足")
                return ProcessResponse.success()
            except Exception as e:
                return ProcessResponse.fail(msg="商品不存在")
        else:
            # 命中缓存的话, 使用lua脚本执行减少库存, 确保原子性
            result = redis_client.pre_reduce_stock(id, quantity)
            if result == 1:
                update_goods_stock.delay(id=id, quantity=quantity)
                return ProcessResponse.success()
            else:
                return ProcessResponse.success(msg="库存不足", code=500)

    @staticmethod
    def clear_cache():
        """ 清空缓存 """
        redis_client.clear_cache()
        return ProcessResponse.success()
